// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.Contracts; using System.Linq; using JetBrains.Annotations; using LargoCommon.Abstract; using LargoCommon.Interfaces; using LargoCommon.Localization; namespace LargoCommon.Music { /// /// Musical Part. /// public sealed class MusicalPart { #region Fields /// /// Musical Block. /// private MusicalBlock musicalBlock; /// /// Musical Track. /// private IList musicalTracks; /// /// Musical Objects. /// private Collection musicalObjects; #endregion #region Constructors /// /// Initializes a new instance of the MusicalPart class. /// /// The given block. public MusicalPart(MusicalBlock givenBlock) { this.MusicalBlock = givenBlock; this.MusicalLines = new List(); this.MusicalObjects = new Collection(); } /// /// Initializes a new instance of the class. /// [UsedImplicitly] public MusicalPart() { } #endregion #region Public properties /// /// Gets Musical Lines. /// /// Property description. public IList MusicalLines { get { Contract.Ensures(Contract.Result>() != null); return this.musicalTracks ?? (this.musicalTracks = new List()); } //// Remove private set - DevExpress private set => this.musicalTracks = value; } /// /// Gets or sets identifier. /// /// Property description. public string PartId { get; set; } /// /// Gets or sets Instrument. /// /// Property description. public MusicalInstrument Instrument { get; set; } /// /// Gets or sets Channel. /// /// Property description. public MidiChannel Channel { get; set; } /// Gets or sets purpose of the track. /// Property description. /// Returns value. public LinePurpose Purpose { get; set; } //// CA1044 (FxCop) /// /// Gets or sets composed file. /// /// Property description. /// /// Gets or sets musical block. /// /// Property description. private MusicalBlock MusicalBlock { get { Contract.Ensures(Contract.Result() != null); if (this.musicalBlock == null) { throw new InvalidOperationException("Musical block is null."); } return this.musicalBlock; } set => this.musicalBlock = value ?? throw new ArgumentException(LocalizedMusic.String("Argument cannot be null."), nameof(value)); } #endregion #region Private properties /// /// Gets or sets Part Number. /// /// Property description. // ReSharper disable once UnusedAutoPropertyAccessor.Local private int PartNumber { [UsedImplicitly] get; set; } /// /// Gets or sets Musical Tones. /// /// Property description. private Collection MusicalObjects { get { Contract.Ensures(Contract.Result>() != null); return this.musicalObjects ?? (this.musicalObjects = new Collection()); } set => this.musicalObjects = value; } #endregion #region Static factory methods /// /// Gets new musical track. /// /// The musical block. /// Number of part. /// Midi Channel. /// /// Returns value. /// public static MusicalPart GetNewMusicalPart(MusicalBlock musicalBlock, int partNumber, MidiChannel givenChannel) { var part = GetNewMusicalPart(musicalBlock); part.PartNumber = partNumber; part.Channel = givenChannel; return part; } #endregion #region Public methods /// Add on musical tone to the end of part. /// Musical object - tone or shift. public void AddMusicalObject(IMusicalLocation musicalObject) { Contract.Requires(musicalObject != null); //// if (musicalObject == null) { return; } this.MusicalObjects.Add(musicalObject); } /// /// Moves the objects to staff tracks. /// public void MoveObjectsToStaffTracks() { //// MusicalTones group by staff and voice var trackGroups = (from mt in this.MusicalObjects select new { mt.Staff, mt.InstrumentNumber }).Distinct().ToList(); //// mt.Channel this.MusicalLines = new List(); foreach (var tg in trackGroups) { var tg1 = tg; var voiceObjects = (from mt in this.MusicalObjects where mt.Staff == tg1.Staff && mt.InstrumentNumber == tg1.InstrumentNumber //// && mt.Channel == tg1.Channel orderby mt.BarNumber select mt).ToList(); if (!voiceObjects.Any()) { continue; } var line = MusicalLine.GetNewMusicalLine(MusicalLineType.Melodic, this.MusicalBlock); line.FirstStatus.Instrument = new MusicalInstrument((MidiMelodicInstrument)tg.InstrumentNumber); //// track.FirstStatus.Channel = this.Channel; //// track.FirstStatus.GChannel = new GeneralChannel(InstrumentGenus.Melodical, tg.Instrument, this.Channel); line.Purpose = this.Purpose; //// track.Purpose = this.Purpose; //// 2019/01 this.MusicalLines.Add(line); voiceObjects.ForAll(musicalObject => { if (musicalObject is MusicalStrike tone) { line.AddMusicalTone(tone); } }); } } /// /// Lays the objects to voice tracks. /// public void LayObjectsToVoiceTracks() { //// MusicalTones group by staff and voice var trackGroups = (from mt in this.MusicalObjects select new { mt.Staff, mt.Voice }).Distinct().ToList(); this.MusicalLines = new List(); foreach (var tg in trackGroups) { var tg1 = tg; var voiceObjects = (from mt in this.MusicalObjects where mt.Staff == tg1.Staff && mt.Voice == tg1.Voice select mt).ToList(); if (!voiceObjects.Any()) { continue; } var line = MusicalLine.GetNewMusicalLine(0, this.MusicalBlock); line.FirstStatus.Instrument = this.Instrument; line.MainVoice.Channel = this.Channel; //// track.Status.GChannel = new GeneralChannel(InstrumentGenus.Melodical, this.Instrument, this.Channel); line.Purpose = this.Purpose; //// track.Purpose = this.Purpose; //// 2019/01 this.MusicalLines.Add(line); //// Values of BitFrom must be determined here !!! var bitFrom = 0; var lastBarNumber = -1; voiceObjects.ForAll(musicalObject => { if (musicalObject.BarNumber != lastBarNumber) { bitFrom = 0; lastBarNumber = musicalObject.BarNumber; } if (musicalObject is MusicalShift shift) { bitFrom = bitFrom + shift.Value; } // ReSharper disable once InvertIf if (musicalObject is MusicalStrike tone && bitFrom >= 0) { tone.BitFrom = (byte)bitFrom; line.AddMusicalTone(tone); bitFrom = bitFrom + tone.Duration; } }); //// track.MusicalOctave = track.MusicalTones. } } #endregion #region Private methods /// /// Gets new musical track. /// /// The given block. /// /// Returns value. /// private static MusicalPart GetNewMusicalPart(MusicalBlock givenBlock) { var part = new MusicalPart(givenBlock); return part; } #endregion } }